#include "stdafx.h"
#include "StatusChecker.h"
#include "Noncopyable.h"

#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>

// Thanks for this link:
// http://msdn.microsoft.com/en-us/library/windows/apps/hh279672.aspx

class StatusChecker : public Noncopyable
{
public:
	explicit StatusChecker(int id) : _id(id), _status("On")
	{
		std::cout << "Createing one checker " << _id << std::endl;
	}

	~StatusChecker()
	{
		std::cout << "Destroying one checker " << _id << std::endl;
	}

	// Getter for id
	int Id() const { return _id; }

	// Getter for id
	std::string Status() const { return _status; }

	// Getter the others, note: we doesn't return the value although it's a move operation
	// since we need to push_back item to this container
	std::vector<std::weak_ptr<StatusChecker>>& Others() { return _others; }

	// Demonstrates how to test whether the 
	// pointed-to memeory still exists or not.
	void CheckStatues() const
	{
		std::for_each(std::begin(_others), std::end(_others),
			[&](const std::weak_ptr<StatusChecker>& other) {
			auto p = other.lock();
			if (p) {
				std::cout << "Status of " << p->Id() << " = " << p->Status() << std::endl;
			}
			else {
				std::cout << "Null object" << std::endl;
			}
		});
	}

private:
	int _id;
	std::string _status;
	std::vector<std::weak_ptr<StatusChecker>> _others;
};

void CheckStatusesAction(void)
{
	std::vector<std::shared_ptr<StatusChecker>> samples;
	for (int i = 0; i < 5; i++) {
		samples.push_back(std::make_shared<StatusChecker>(i));
	}

	// Each checker depends on all others not being deleted.
	// Give each checker a pointer to all others.
	// Here, for 'samples' we pass a value(but reference) to lambda body
	// so there is copy consturct here, since it's not RValue reference. 
	// but, why the result is correct, 'Cause the shared_ptr effects here,
	// it's shared the between the old and new vectors
	// so the better choice is that always declear it as reference
	// as you seen, the STL container plus smart pointer is powerful!
	// In gerneral, vector with shared_ptr is better choice in this case
	for (int i = 0; i < samples.size(); i++)
	{
		std::for_each(std::begin(samples), std::end(samples), [&, samples, i]( // copy a new vector
			const std::shared_ptr<StatusChecker>& sample) {
			if (sample->Id() != i) {
				samples[i]->Others().push_back(std::weak_ptr<StatusChecker>(sample));
				std::cout << "Push back to v[" << i << "]: " << sample->Id() << std::endl;
			}
		});
	}

	// Try to release the last one
	samples.pop_back();

	// Check overall statues
	std::for_each(std::begin(samples), std::end(samples), [&](
		const std::shared_ptr<StatusChecker>& sample) {
		std::cout << "user_count = " << sample.use_count() << std::endl;
		sample->CheckStatues();
	});

}

	void containerDestoryTestAction(void)
	{
		std::vector<StatusChecker*> rawPointers;

		std::cout << "Alloc 5 checkers" << std::endl;

		for (int i = 0; i < 5; i++)
		{
			std::cout << "Push back " << i << " to container" << std::endl;
			rawPointers.push_back(new StatusChecker(i));
		}

		std::cout << "Call clear to try destroy those raw pointers" << std::endl;

		/// Recap:
		// The STL container don't call delete or delete[] to release the raw pointers
		// You should always alloc a raw point to smart point regarding RAII(resource acquisition is initializtion)
		// only like that, RRID (resource release is destructor) will effect to ensure resource
		// release correctly
	}